structure T = Tokens
structure E = ErrorMsg

type pos = int

type svalue = Tokens.svalue
type ('a,'b) token = ('a,'b) Tokens.token
type lexresult  = (svalue,pos) token

val lineNum = E.lineNum
val linePos = E.linePos
  
val eof = (fn () => let val pos = hd(!linePos)
                    in  Tokens.EOF(pos, pos)
                    end)

val printTag = ref true
fun tok (t, text, l, r) =
  let val _ = if !printTag
  then print (String.concat [text, "\n"])
  else ()
  in  t (l, r)
  end

fun tok2 (t, text, l, r) = 
         let val _ = if !printTag
  then print (String.concat [text, "\n"])
  else ()
  in  t (text, l, r)
  end

%%

%header (functor CLexFun(structure Tokens: C_TOKENS));
%s COMMENT LCOMMENT ASSERT;
letter=[_a-zA-Z];
al=[_0-9a-zA-Z];
digit=[0-9];
id=({letter})({letter}|{digit})*;
ws=[\ \t];
%%
<INITIAL>{ws}+ 	        => (continue());
<INITIAL>"->"           => (Tokens.ARROW (yypos, yypos + size yytext));
<INITIAL>"."            => (Tokens.DOT (yypos, yypos + size yytext));
<INITIAL>","            => (Tokens.COMMA (yypos, yypos + size yytext));
<INITIAL>";"		=> (Tokens.SEMICOLON(yypos, yypos + size yytext));
<INITIAL>"("		=> (Tokens.LPAREN(yypos, yypos + size yytext));
<INITIAL>")"            => (Tokens.RPAREN(yypos, yypos + size yytext));
<INITIAL>"{"            => (tok (Tokens.LBRACE, yytext, yypos,yypos + size yytext));
<INITIAL>"}"            => (tok (Tokens.RBRACE, yytext, yypos,yypos + size yytext));
<INITIAL>"["            => (tok (Tokens.LBRACK, yytext, yypos,yypos + size yytext));
<INITIAL>"]"            => (tok (Tokens.RBRACK, yytext, yypos,yypos + size yytext));
<INITIAL>"+"            => (tok (Tokens.PLUS, yytext, yypos, yypos + size yytext));
<INITIAL>"-"            => (Tokens.MINUS(yypos, yypos + size yytext));
<INITIAL>"*"            => (tok (Tokens.TIMES, yytext, yypos, yypos + size yytext));
<INITIAL>"/"            => (tok (Tokens.DIVIDE, yytext, yypos, yypos + size yytext));
<INITIAL>"%"            => (tok (Tokens.MODUS, yytext, yypos, yypos + size yytext));
<INITIAL>">="           => (Tokens.GE(yypos,yypos + size yytext));
<INITIAL>">"            => (Tokens.GT(yypos,yypos + size yytext));
<INITIAL>"<="           => (Tokens.LE(yypos,yypos + size yytext));
<INITIAL>"<"            => (Tokens.LT(yypos,yypos + size yytext));
<INITIAL>"=="           => (Tokens.EQ(yypos,yypos + size yytext));
<INITIAL>"!="           => (Tokens.NEQ(yypos,yypos + size yytext));
<INITIAL>"&&"           => (Tokens.AND(yypos,yypos + size yytext));
<INITIAL>"||"           => (Tokens.OR(yypos,yypos + size yytext));
<INITIAL>"!"            => (Tokens.NOT(yypos,yypos + size yytext));
<INITIAL>"="            => (Tokens.ASSIGN(yypos, yypos + size yytext));

<INITIAL>"enum"         => (tok (Tokens.ENUM, yytext, yypos, yypos + size yytext));
<INITIAL>"int"          => (tok (Tokens.INT, yytext, yypos, yypos + size yytext));
<INITIAL>"void"         => (Tokens.VOID(yypos, yypos + size yytext));
<INITIAL>"if"             => (Tokens.IF(yypos, yypos + size yytext));
<INITIAL>"else"           => (Tokens.ELSE(yypos, yypos + size yytext));
<INITIAL>"while"          => (Tokens.WHILE(yypos, yypos + size yytext));
<INITIAL>"struct"         => (Tokens.STRUCT(yypos, yypos + size yytext));
<INITIAL>"return"         => (Tokens.RETURN(yypos, yypos + size yytext));

<INITIAL>"/*"		=> (YYBEGIN COMMENT; continue());
<INITIAL>"//"		=> (YYBEGIN LCOMMENT; continue());
<COMMENT>"*/"		=> (YYBEGIN INITIAL; continue());
<LCOMMENT>"\n"		=> (YYBEGIN INITIAL; lineNum := !lineNum+1; linePos := yypos :: !linePos; continue());
<COMMENT,LCOMMENT>.	=> (continue());


<INITIAL>{id}           => (tok2 (Tokens.ID, yytext, yypos, yypos + size yytext));
<INITIAL>{digit}+	=> (tok2 (Tokens.INTCONST, yytext, yypos, yypos + size yytext));
<INITIAL,COMMENT>\n	=> (lineNum := !lineNum+1; linePos := yypos :: !linePos; continue());
<INITIAL>.       	=> (E.error yypos ("Invalid character: "^yytext); continue());
